package main

import (
	"fmt"
	"hello/src/models"
	_ "hello/src/models"
	_ "hello/src/utils"
	"unsafe"
)

var (
	n1 = 500
	s1 = "hello"
)

/* 声明全局变量 */
var g2 int

const (
	Unknown = 0
	Female  = 1
	Male    = 2

	a5 = "abc"
	b5 = len(a5)
	c5 = unsafe.Sizeof(a5)

	a6 = iota //0
	b6        //1
	c6        //2

	d6 = "ha" //独立值，iota += 1
	e6        //"ha"   iota += 1
	f6 = 100  //iota +=1
	g6        //100  iota +=1

	h6 = iota //7,恢复计数
	i6        //8

	//<<n==*(2^n) 左移
	i = 1 << iota
	j = 3 << iota
	k
	l
)

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

type Books struct {
	title   string
	author  string
	subject string
	book_id int
}

func main() {
	fmt.Println("======================================")
	baseT()

	fmt.Println("默认初始值=====================================")
	defaultValues()

	fmt.Println("函数一次返回多个值=====================================")
	funcValues()

	fmt.Println("全局变量=======================")
	globalVariable()

	fmt.Println("运算符=======================")
	operator()

	fmt.Println("关系运算符=======================")
	relationalOperator()

	fmt.Println("逻辑运算符=======================")
	logicalOperator()

	fmt.Println("位运算符=======================")
	bitwiseOperators()

	fmt.Println("循环=======================")
	circle()

	fmt.Println("数组1=======================")
	numList()

	fmt.Println("数组2=======================")
	numList2()

	fmt.Println("指针1=======================")
	pointer1()

	fmt.Println("指针做入参=======================")
	pointer2()

	fmt.Println("指针指向指针=======================")
	pointer3()

	fmt.Println("struct=======================")
	struct1()

	fmt.Println("切片Slice=======================")
	slice1()
	fmt.Println("切片nilSlice=======================")
	nilSlice()
	fmt.Println("切片Slice2=======================")
	slice2()
	fmt.Println("切片Slice3,append() 和 copy()=====================")
	slice3()

	fmt.Println("切片Range1=====================")
	fmt.Println("在数组和切片中它返回元素的索引和索引对应的值，在集合中返回 key-value 对")
	fmt.Println("for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环")
	range1()
	fmt.Println("切片Range2=====================")
	range2()
	fmt.Println("切片Range3=====================")
	range3()

	fmt.Println("自定义对象的使用=====================")
	info := models.Project{}
	info.TableName()

	s := models.Student{}
	s.Init("pirlo", 21, "cs")
	s.SayHi()

	r := models.Rectangle{Length: 4, Width: 2}
	// 调用 Area() 方法，计算面积
	fmt.Println(r.Area())

	fmt.Println("Map1=====================")
	Map1()
	fmt.Println("MapDel=====================")
	Map2()
	fmt.Println("HashMap=====================")
	//hashMap := new(utils.HashMap)
	//hashMap := utils.HashMap{}

	fmt.Println("interface=====================")
	inter1()

	fmt.Println("interface2=====================")
	inter2()
}

func inter1() {
	car := models.Car{}
	carF := car.GoToWorkIn()
	fmt.Println(carF)
}

func inter2() {
	var animal models.Animal

	animal = models.Dog{}
	animal.Move()
	animal.Shout()

	animal = models.Bird{}
	animal.Move()
	animal.Shout()
}

func Map2() {
	/* 创建map */
	countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}
	fmt.Println("原始地图")

	/* 打印地图 */
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}

	/*删除元素*/
	delete(countryCapitalMap, "France")
	fmt.Println("法国条目被删除")

	fmt.Println("删除元素后地图")
	/*打印地图*/
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}
}

func Map1() {
	var siteMap map[string]string /*创建集合 */
	siteMap = make(map[string]string)

	/* map 插入 key - value 对,各个国家对应的首都 */
	siteMap["Google"] = "谷歌"
	siteMap["Runoob"] = "菜鸟教程"
	siteMap["Baidu"] = "百度"
	siteMap["Wiki"] = "维基百科"

	/*使用键输出地图值 */
	for i := range siteMap {
		fmt.Println(i, "首都是", siteMap[i])
	}

	/*查看元素在集合中是否存在 */
	name, ok := siteMap["Facebook"]
	/*如果确定是真实的,则存在,否则不存在 */
	if ok {
		fmt.Println("Facebook 的 站点是", name)
	} else {
		fmt.Println("Facebook 站点不存在")
	}
}

func range3() {
	//这是我们使用 range 去求一个 slice 的和。使用数组跟这个很类似
	nums := []int{2, 3, 4}
	sum := 0
	for _, num := range nums {
		sum += num
	}
	fmt.Println("sum:", sum)

	//在数组上使用 range 将传入索引和值两个变量。上面那个例子我们不需要使用该元素的序号，所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
	for i, num := range nums {
		if num == 3 {
			fmt.Println("index:", i)
		}
	}

	//range 也可以用在 map 的键值对上。
	kvs := map[string]string{"a": "apple", "b": "banana"}
	for k, v := range kvs {
		fmt.Printf("%s -> %s\n", k, v)
	}

	//range也可以用来枚举 Unicode 字符串。第一个参数是字符的索引，第二个是字符（Unicode的值）本身。
	for i, c := range "go" {
		fmt.Println(i, c)
	}
}

func range2() {
	map1 := make(map[int]float32)
	map1[1] = 1.0
	map1[2] = 2.0
	map1[3] = 3.0
	map1[4] = 4.0

	// 读取 key 和 value
	for key, value := range map1 {
		fmt.Printf("key is: %d - value is: %f\n", key, value)
	}

	// 读取 key
	for key := range map1 {
		fmt.Printf("key is: %d\n", key)
	}

	// 读取 value
	for _, value := range map1 {
		fmt.Printf("value is: %f\n", value)
	}
}

func range1() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

func slice3() {
	var numbers []int
	printSlice(numbers)

	/* 允许追加空切片 */
	numbers = append(numbers, 0)
	printSlice(numbers)

	/* 向切片添加一个元素 */
	numbers = append(numbers, 1)
	printSlice(numbers)

	/* 同时添加多个元素 */
	numbers = append(numbers, 2, 3, 4)
	printSlice(numbers)

	/* 创建切片 numbers1 是之前切片的两倍容量*/
	numbers1 := make([]int, len(numbers), (cap(numbers))*2)

	/* 拷贝 numbers 的内容到 numbers1 */
	copy(numbers1, numbers)
	printSlice(numbers1)
}

func slice2() {
	/* 创建切片 */
	numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
	printSlice(numbers)

	/* 打印原始切片 */
	fmt.Println("numbers ==", numbers)

	/* 打印子切片从索引1(包含) 到索引4(不包含)*/
	fmt.Println("numbers[1:4] ==", numbers[1:4])

	/* 默认下限为 0*/
	fmt.Println("numbers[:3] ==", numbers[:3])

	/* 默认上限为 len(s)*/
	fmt.Println("numbers[4:] ==", numbers[4:])

	numbers1 := make([]int, 0, 5)
	printSlice(numbers1)

	/* 打印子切片从索引  0(包含) 到索引 2(不包含) */
	number2 := numbers[:2]
	printSlice(number2)

	/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
	number3 := numbers[2:5]
	printSlice(number3)
}

func nilSlice() {
	var numbers []int
	printSlice(numbers)
	if numbers == nil {
		fmt.Printf("切片是空的")
	}
}

func slice1() {
	var numbers = make([]int, 3, 5)
	printSlice(numbers)
}

func printSlice(x []int) {
	fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func struct1() {
	// 创建一个新的结构体
	fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})

	// 也可以使用 key => value 格式
	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})

	// 忽略的字段为 0 或 空
	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})

	var Book1 Books /* 声明 Book1 为 Books 类型 */
	var Book2 Books /* 声明 Book2 为 Books 类型 */

	/* book 1 描述 */
	Book1.title = "Go 语言"
	Book1.author = "www.runoob.com"
	Book1.subject = "Go 语言教程"
	Book1.book_id = 6495407

	/* book 2 描述 */
	Book2.title = "Python 教程"
	Book2.author = "www.runoob.com"
	Book2.subject = "Python 语言教程"
	Book2.book_id = 6495700

	/* 打印 Book1 信息 */
	fmt.Printf("Book 1 title : %s\n", Book1.title)
	fmt.Printf("Book 1 author : %s\n", Book1.author)
	fmt.Printf("Book 1 subject : %s\n", Book1.subject)
	fmt.Printf("Book 1 book_id : %d\n", Book1.book_id)

	/* 打印 Book2 信息 */
	fmt.Printf("Book 2 title : %s\n", Book2.title)
	fmt.Printf("Book 2 author : %s\n", Book2.author)
	fmt.Printf("Book 2 subject : %s\n", Book2.subject)
	fmt.Printf("Book 2 book_id : %d\n", Book2.book_id)
}

func pointer3() {
	var a int
	var ptr *int
	var pptr **int

	a = 3000

	/* 指针 ptr 地址 */
	ptr = &a

	/* 指向指针 ptr 地址 */
	pptr = &ptr

	/* 获取 pptr 的值 */
	fmt.Printf("变量 a = %d\n", a)
	fmt.Printf("指针变量 *ptr = %d\n", *ptr)
	fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}

func pointer2() {
	var a int = 100
	var b int = 200

	fmt.Printf("交换前 a 的值 : %d\n", a)
	fmt.Printf("交换前 b 的值 : %d\n", b)

	/* 调用函数用于交换值
	 * &a 指向 a 变量的地址
	 * &b 指向 b 变量的地址
	 */
	swap(&a, &b)

	fmt.Printf("交换后 a 的值 : %d\n", a)
	fmt.Printf("交换后 b 的值 : %d\n", b)
}

func pointer1() {
	var a10 int = 20 /* 声明实际变量 */
	var ip *int      /* 声明指针变量 */

	ip = &a10 /* 指针变量的存储地址 */

	fmt.Printf("a10 变量的地址是: %x\n", &a10)

	/* 指针变量的存储地址 */
	fmt.Printf("ip 变量储存的指针地址: %x\n", ip)

	/* 使用指针访问值 */
	fmt.Printf("*ip 变量的值: %d\n", *ip)

	//空指针
	var ptr *int
	fmt.Printf("ptr 的值为 : %x\n", ptr)
	if ptr != nil {
		fmt.Println("ptr 不是空指针")
	}
	if ptr == nil {
		fmt.Println("ptr 是空指针")
	}
}

func swap(x *int, y *int) {
	var temp int
	temp = *x /* 保存 x 地址的值 */
	*x = *y   /* 将 y 赋值给 x */
	*y = temp /* 将 temp 赋值给 y */
}

func numList2() {
	var i, j, k int
	// 声明数组的同时快速初始化数组
	balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

	/* 输出数组元素 */
	for i = 0; i < 5; i++ {
		fmt.Printf("balance[%d] = %f\n", i, balance[i])
	}

	balance2 := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
	/* 输出每个数组元素的值 */
	for j = 0; j < 5; j++ {
		fmt.Printf("balance2[%d] = %f\n", j, balance2[j])
	}

	//  将索引为 1 和 3 的元素初始化
	balance3 := [5]float32{1: 2.0, 3: 7.0}
	for k = 0; k < 5; k++ {
		fmt.Printf("balance3[%d] = %f\n", k, balance3[k])
	}
}

func baseT() {
	fmt.Println("hello,world")

	var age1 int = 19
	fmt.Println(age1)

	age2 := 20
	fmt.Println(age2)

	// %d 表示整型数字，%s 表示字符串
	var stockCode = 123
	var endDate = "2020-12-31"
	var url = "Code=%d&endDate=%s"
	var targetUrl = fmt.Sprintf(url, stockCode, endDate)
	fmt.Println(targetUrl)

	// %d 表示整型数字，%s 表示字符串
	stockCode1 := 123
	endDate1 := "2020-12-31"
	url1 := "Code=%d&endDate=%s"
	fmt.Printf(url1, stockCode1, endDate1)
	fmt.Println()

	fmt.Println("=================================================")
	var a1 string = "Runoob"
	fmt.Println(a1)

	var b1, c1 int = 1, 2
	fmt.Println(b1, c1)

	// 声明一个变量并初始化
	var a2 = "RUNOOB"
	fmt.Println(a2)

	// 没有初始化就为零值
	var b3 int
	fmt.Println(b3)

	// bool 零值为 false
	var c3 bool
	fmt.Println(c3)
}

func defaultValues() {
	var i1 int
	var f1 float64
	var g1 bool
	var s1 string
	fmt.Printf("%v %v %v %q\n", i1, f1, g1, s1)
}

func funcValues() {
	_, numb, stars := numbers() //只获取函数返回值的后两个
	fmt.Println(numb, stars)

	fmt.Println("语言常量：在程序运行时，不会被修改的量=======================")
	const LENGTH int = 10
	const WIDTH int = 5
	var area int
	const a4, b4, c4 = 1, false, "str" //多重赋值

	area = LENGTH * WIDTH
	fmt.Printf("面积为 : %d", area)
	println()
	println(a4, b4, c4)
}

func globalVariable() {
	println(Unknown, Female, Male)
	println(a5, b5, c5)
	println(a6, b6, c6, d6, e6, f6, g6, h6, i6)
}

func operator() {
	var a7 int = 21
	var b7 int = 10
	var c7 int

	c7 = a7 + b7
	fmt.Printf("第一行 - c7 的值为 %d\n", c7)
	c7 = a7 - b7
	fmt.Printf("第二行 - c7 的值为 %d\n", c7)
	c7 = a7 * b7
	fmt.Printf("第三行 - c7 的值为 %d\n", c7)
	c7 = a7 / b7
	fmt.Printf("第四行 - c7 的值为 %d\n", c7)
	c7 = a7 % b7
	fmt.Printf("第五行 - c7 的值为 %d\n", c7)
	a7++
	fmt.Printf("第六行 - a7 的值为 %d\n", a7)
	a7 = 21 // 为了方便测试，a7 这里重新赋值为 21
	a7--
	fmt.Printf("第七行 - a7 的值为 %d\n", a7)
}

func relationalOperator() {
	var a int = 21
	var b int = 10

	if a == b {
		fmt.Printf("第一行 - a8 等于 b8\n")
	} else {
		fmt.Printf("第一行 - a8 不等于 b8\n")
	}
	if a < b {
		fmt.Printf("第二行 - a8 小于 b8\n")
	} else {
		fmt.Printf("第二行 - a8 不小于 b8\n")
	}

	if a > b {
		fmt.Printf("第三行 - a8 大于 b8\n")
	} else {
		fmt.Printf("第三行 - a8 不大于 b8\n")
	}
	/* Lets change value of a8 and b8 */
	a = 5
	b = 20
	if a <= b {
		fmt.Printf("第四行 - a8 小于等于 b8\n")
	}
	if b >= a {
		fmt.Printf("第五行 - b8 大于等于 a8\n")
	}
}

func logicalOperator() {
	a8 := true
	b8 := false
	if a8 && b8 {
		fmt.Printf("第一行 - 条件为 true\n")
	}
	if a8 || b8 {
		fmt.Printf("第二行 - 条件为 true\n")
	}
	/* 修改 a8 和 b8 的值 */
	a8 = false
	b8 = true
	if a8 && b8 {
		fmt.Printf("第三行 - 条件为 true\n")
	} else {
		fmt.Printf("第三行 - 条件为 false\n")
	}
	if !(a8 && b8) {
		fmt.Printf("第四行 - 条件为 true\n")
	}
}

func bitwiseOperators() {
	var a9 uint = 60 /* 60 = 0011 1100 */
	var b9 uint = 13 /* 13 = 0000 1101 */
	var c9 uint = 0

	c9 = a9 & b9 /* 12 = 0000 1100 */
	fmt.Printf("第一行 - c9 的值为 %d\n", c9)

	c9 = a9 | b9 /* 61 = 0011 1101 */
	fmt.Printf("第二行 - c9 的值为 %d\n", c9)

	c9 = a9 ^ b9 /* 49 = 0011 0001 */
	fmt.Printf("第三行 - c9 的值为 %d\n", c9)

	c9 = a9 << 2 /* 240 = 1111 0000 */
	fmt.Printf("第四行 - c9 的值为 %d\n", c9)

	c9 = a9 >> 2 /* 15 = 0000 1111 */
	fmt.Printf("第五行 - c9 的值为 %d\n", c9)
}

func circle() {
	//for true{
	//	fmt.Printf("这是无限循环。\n");
	//}
}

func numList() {
	var n [10]int /* n 是一个长度为 10 的数组 */
	var i, j int

	/* 为数组 n 初始化元素 */
	for i = 0; i < 10; i++ {
		n[i] = i + 100 /* 设置元素为 i + 100 */
	}

	/* 输出每个数组元素的值 */
	for j = 0; j < 10; j++ {
		fmt.Printf("Element[%d] = %d\n", j, n[j])
	}
}

// 一个可以返回多个值的函数
func numbers() (int, int, string) {
	a, b, c := 1, 2, "str"
	return a, b, c
}
